/**
 * @this FormItemHOC: hook FormItem
 *
 * 可以移植的 Form
 *
 * @flow
 */
import React, { Component } from 'react'
import PropTypes from 'prop-types'

import CDItemManager from '../core/FormItemManager'
import CDFormValidation from '../config/FormValidation'
import FormToast from '../config/FormToast'
// import FormItemValidationType from '../config/FormItemValidationType'

export default (WrappedComponent) => {
  return class PackComponent extends Component {
    constructor(props, content) {
      super(props, content)

      this.childrenRefs = {}
      this.hit = null
      this.formSelfRef = null
    }

    static propTypes = {
      ...WrappedComponent.propTypes,
      hitView: PropTypes.bool,
      onToast: PropTypes.func,
      formValidate: PropTypes.bool,
      onValidate: PropTypes.func,
      validateEvery: PropTypes.bool,
      onSubmitSuccess: PropTypes.func,
      formRef: PropTypes.func,
    }

    static defaultProps = {
      ...WrappedComponent.defaultProps,
      hitView: false,
      formValidate: true,
      onValidate: () => { return true },
      validateEvery: false,
      onSubmitSuccess: () => {},
      formRef: (e) => {},
    }

    UNSAFE_componentWillMount() {
      this.formName = new Date().getTime()
      CDItemManager.initForm(this.formName)
    }

    componentWillUnmount() {
      CDItemManager.reset(this.formName)
      this.formName = undefined
    }

    _forceUpdate = () => {
      this.forceUpdate()
    }

    _submit = () => {
      const { onValidate, onSubmitSuccess } = this.props
      this.submitAction() && onValidate() && onSubmitSuccess && onSubmitSuccess()
    }

    submitAction = () => {
      const { formValidate } = this.props

      if (formValidate) {
        if (this.props.validateEvery) {
          let result = true
          const array = this.buildChildren()
          for (let i = 0; i < array.length; i++) {
            const item = array[i]
            if (!item) continue
            const validate = this.letlidateItem(item, i)
            if (!validate && result) {
              result = false
            }
          }
          return result
        } else {
          return this.buildChildren().every((item, index) => {
            return this.letlidateItem(item, index)
          })
        }
      }
      return true
    }

    letlidateItem = (item, index) => {
      if (!item) return true// 防止 undefined 或者 null
      const { submitButton } = item.props
      let validate = false

      validate = this._validateAction(item, index)
      !validate && this.childrenRefs[index]._doFailAnimate && this.childrenRefs[index]._doFailAnimate({ index, tip: this.props.hitView, hit: this.hit })
      return submitButton || validate
    }

    _validateAction = (item, index) => {
      let { onToast } = this.props
      const { validators, title } = item.props
      let value = CDItemManager.getValue(this.formName, index)
      if (typeof value === 'number') {
        value = '' + value
      }
      const { formItemType, weakValidator } = this._getItemAllProps(item, index)
      // const value = this._formatItemValue(tempValue, formItemType, item, index)

      const itemTitle = title || ''
      if (onToast === undefined) {
        onToast = FormToast.showMessage
      }

      this.hit = null

      if (validators && validators.length) {
        return validators.every((validate, vIndex) => {
          let result = true
          if (typeof validate === 'string') {
            result = CDFormValidation.passWithName(validate, value)
            if (this.props.hitView) {
              // 信息提示是写死的，不能起到定制的作用，以后需改进
              // 具体请看 ErrorNullInfo.js
              if (!result && !weakValidator) {
                const hit = item.props.hit // 自定义错误信息
                if (!(hit && typeof hit === 'string' && hit.length)) {
                  this._setHint(itemTitle, formItemType, item, vIndex)
                }
              } else {
                return true
              }
            } else {
              if (!value && weakValidator) return true

              let hint = ''
              const hit = item.props.hit // 自定义错误信息
              if (hit && typeof hit === 'string' && hit.length) {
                hint = hit // 配置单个 toash
              }

              const hintPrefix = CDFormValidation.hintWithType(formItemType) || ''
              const hits = item.props.hits || []
              if (hits && Array.isArray(hits) && hits.length > vIndex) {
                // 配置多个 toash
                const tempHit = hits[vIndex]
                if (tempHit && typeof tempHit === 'string' && tempHit.length) {
                  hint = tempHit
                }
              }
              if (!hint || !(typeof hint === 'string') && hint.length > 0) {
                // 没有配置 toash， 采用默认的
                if (!value) {
                  hint = hintPrefix + CDFormValidation.messageWithName(validate, itemTitle)
                } else {
                  this._setHint(itemTitle, formItemType, item, vIndex)
                  hint = this.hit
                }
              }
              !result && onToast(hint)
            }
          } else if (typeof validate === 'function') {
            if (value) {
              result = validate(value)
            }
            if (this.props.hitView) {
              if (!result && !weakValidator) {
                const hit = item.props.hit // 自定义错误信息
                if (!(hit && typeof hit === 'string' && hit.length)) {
                  this._setHint(itemTitle, formItemType, item, vIndex)
                }
              } else {
                return true
              }
            } else {
              if (value) {
                if (!result) {
                    let hint = ''
                    const hit = item.props.hit // 自定义错误信息
                    if (hit && typeof hit === 'string' && hit.length) {
                      hint = hit // 配置单个 toash
                    } else {
                      this._setHint(itemTitle, formItemType, item, vIndex)
                      hint = this.hit
                    }
                    onToast(hint)
                }
              } else {
                  // value 为空的判断
                  if (!weakValidator) {
                    const hintPrefix = CDFormValidation.hintWithType(formItemType) || ''
                    const hint = hintPrefix + CDFormValidation.messageWithName(validate, itemTitle)
                    onToast(hint)
                    return false
                  }
              }
            }
          } else {
            console.warn('validators数组传入规则不正确')
          }
          return result
        })
      }

      return true
    }

    // 不为空的 判断
    _setHint(title, formItemType, item, index) {
      const { hits } = item.props
      if (hits && Array.isArray(hits) && hits.length > index) {
        this.hit = hits[index] || null
        return
      }
      let hint = '有误，请重新填写'
      if (formItemType && formItemType === 'input') {
        hint = '格式有误，请重新输入'
      } else if (formItemType && formItemType === 'select') {
        hint = '有误，请重新选择'
      } else if (formItemType && formItemType === 'checkBox') {
        hint = ''
      }
      this.hit = title + hint
    }

    _getItemAllProps(item, index) {
      // 从 HOC 里面获取 item 所在的位置的 props
      const defaultProps = item.props
      const titleTip = this.childrenRefs[index]
      if (!titleTip) return defaultProps
      const titleTipProps = titleTip.props || {}
      const form = titleTipProps.form || {}
      const childrenRefs = form.childrenRefs || {}
      const completeItem = childrenRefs[index] || {}
      const anim = completeItem.anim || {}
      const animProps = anim.props || {}
      const animChildren = animProps.children || {}
      const completeItemProps = animChildren.props || defaultProps
      return completeItemProps
    }

    // _formatItemValue(value, formItemType, item, index) {
    //   const { type } = this._getItemAllProps(item, index)
    //   let newValue = value
    //   if (newValue && formItemType && formItemType === 'input' && type && type === FormItemValidationType.TypePlateNo) {
    //     newValue = newValue.toLocaleUpperCase()
    //     if (newValue && this.childrenRefs[index]) {
    //       this.childrenRefs[index]._onChange && this.childrenRefs[index]._onChange(newValue)
    //     }
    //   }
    //   return newValue
    // }

    renderChildren = () => {
      this.childrenRefs = {}
      return this.buildChildren().map((item, index) => {
        if (item) {
          return React.cloneElement(item, item.props.submitButton ? {
            key: 'item' + index,
            index,
            form: this,
            onPress: this._submit,
            ref: (e) => { this.childrenRefs[index] = e; item.props.itemRef && item.props.itemRef(e) },
            forceUpdate: this._forceUpdate,
          } : {
              key: 'item' + index,
              index,
              form: this,
              ref: (e) => { this.childrenRefs[index] = e; item.props.itemRef && item.props.itemRef(e) },
              forceUpdate: this._forceUpdate,
            })
        }
        return null
      })
    }

    buildChildren() {
      let { children } = this.props

      if (!children) {
        children = []
      } else if (!(children instanceof Array)) {
        children = [children]
      }

      return children
    }

    __handleRef = (ref: React.ElementRef) => {
      this.formSelfRef = ref
      if (this.props.formRef) {
        this.props.formRef(ref)
      }
    }

    render() {
      const { children, ...other } = this.props
      return (
        <WrappedComponent {...other} ref={this.__handleRef}>
          {this.renderChildren()}
        </WrappedComponent>
      )
    }
  }
}